package cl.zeke.remoto.finders;

import cl.zeke.remoto.negocio.entities.Perfil;
import cl.zeke.remoto.negocio.entities.Usuario;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional(propagation = Propagation.MANDATORY)
public class UsuarioFinder {

    private static Logger log = LoggerFactory.getLogger(UsuarioFinder.class);

    @PersistenceContext
    private EntityManager em;

    public List<Usuario> traerTodos() {
        return em.createNamedQuery("Usuario.traerTodos", Usuario.class)
                .getResultList();
    }

    public Usuario traerPorRut(Integer rut) {
        List<Usuario> lista = em.createNamedQuery("Usuario.traerPorRut")
                .setParameter("rut", rut)
                .getResultList();
        if (lista.isEmpty()) {
            return null;
        }
        return lista.get(0);
    }
    
    public Usuario traerPorEmail(String email) {
        List<Usuario> list = em.createNamedQuery("Usuario.traerPorEmail")
                .setParameter("email", email)
                .getResultList();
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public List<Usuario> buscar(String nombres, String apellidos, Integer rut, Perfil perfil, String email, Date fechaNacimientoInferior, Date fechaNacimientoSuperior, Boolean habilitado, int inicio, int fin) {
        
        String seleccionSQL = "select distinct u ";
        String ordenSQL = "order by u.nombres asc, u.apellidos asc ";
        boolean fetch = true;
        
        Query query = queryUsuarios(nombres, 
                apellidos, 
                rut, 
                perfil, 
                email, 
                fechaNacimientoInferior, 
                fechaNacimientoSuperior, 
                habilitado,
                seleccionSQL,
                ordenSQL,
                fetch);
        
        return query.setFirstResult(inicio)
                .setMaxResults(fin - inicio)
                .getResultList();
    }

    public int buscarRowCount(String nombres, String apellidos, Integer rut, Perfil perfil, String email, Date fechaNacimientoInferior, Date fechaNacimientoSuperior, Boolean habilitado) {
        String seleccionSQL = "select count(distinct u.rut) ";
        String ordenSQL = null;
        boolean fetch = false;
        Query query = queryUsuarios(nombres, 
                apellidos, 
                rut, 
                perfil, 
                email, 
                fechaNacimientoInferior, 
                fechaNacimientoSuperior, 
                habilitado,
                seleccionSQL,
                ordenSQL,
                fetch);
        
        return ((Long)query.getSingleResult()).intValue();
    }

    //PRIVADOS
    private Query queryUsuarios(
            String nombres,
            String apellidos,
            Integer rut,
            Perfil perfil,
            String email,
            Date fechaNacimientoInferior,
            Date fechaNacimientoSuperior,
            Boolean habilitado,
            String seleccionSQL,
            String ordenSQL,
            boolean fetch) {
        Map<String, Object> parametrosMap = new HashMap<>();
        StringBuilder jpqlString = new StringBuilder();

        jpqlString.append(seleccionSQL);
        jpqlString.append("from Usuario u ");

        //joins
        if (fetch) {
            jpqlString.append("inner join fetch u.perfil p ");
        } else {
            jpqlString.append("inner join u.perfil p ");
        }

        //condiciones
        jpqlString.append("where 1=1 ");

        if (nombres != null && !nombres.isEmpty()) {
            jpqlString.append("and upper(u.nombres) like upper(:nombres) ");
            parametrosMap.put("nombres", "%" + nombres + "%");
        }
        if (apellidos != null && !apellidos.isEmpty()) {
            jpqlString.append("and upper(u.apellidos) like upper(:apellidos) ");
            parametrosMap.put("apellidos", "%" + apellidos + "%");
        }
        if (rut != null) {
            jpqlString.append("and u.rut = :rut ");
            parametrosMap.put("rut", rut);
        }
        if (perfil != null) {
            jpqlString.append("and p = :perfil ");
            parametrosMap.put("perfil", perfil);
        }
        if (email != null && !email.isEmpty()) {
            jpqlString.append("and upper(u.email) like upper(:email) ");
            parametrosMap.put("email", "%" + email + "%");
        }
        if (fechaNacimientoInferior != null) {
            jpqlString.append("and u.fechaNacimiento >= :fechaNacimientoInferior ");
            parametrosMap.put("fechaNacimientoInferior", fechaNacimientoInferior);
        }
        if (fechaNacimientoSuperior != null) {
            jpqlString.append("and u.fechaNacimiento <= :fechaNacimientoSuperior ");
            parametrosMap.put("fechaNacimientoSuperior", fechaNacimientoSuperior);
        }
        if (habilitado != null) {
            jpqlString.append("and u.habilitado = :habilitado ");
            parametrosMap.put("habilitado", habilitado);
        }

        if (ordenSQL != null) {
            jpqlString.append(ordenSQL);
        }

        Query query = em.createQuery(jpqlString.toString());
        for (String key : parametrosMap.keySet()) {
            query.setParameter(key, parametrosMap.get(key));
        }

        return query;
    }

}
